﻿#region License

// Copyright (c) 2011, Matt Holmes
// All rights reserved.
// 
// Redistribution and use in source and binary forms, with or without modification, are permitted provided 
// that the following conditions are met:
// 
// * Redistributions of source code must retain the above copyright notice, this list of conditions and the 
//   following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
//   the following disclaimer in the documentation and/or other materials provided with the distribution.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
// OF THE POSSIBILITY OF SUCH DAMAGE.

#endregion

using System;
using System.Linq;
using System.Net;
using System.ServiceModel.Syndication;
using System.Threading.Tasks;
using System.Xml;
using Microsoft.Practices.Prism.Events;

namespace SkyrimTweaker.Common.Services {
	public interface IUpdateService {
		void DownloadUpdate ();
		void StartUpdateCheck (string currentVersion);
	}

	internal class UpdateService : IUpdateService {
		#region Fields

		public const string DownloadPart = "http://skyrimtweaker.googlecode.com/files/";
		public const string UpdateFeed = "http://code.google.com/feeds/p/skyrimtweaker/downloads/basic";

		private readonly IEventAggregator _eventAggregator;
		private string _latestUpdateFile;

		#endregion

		#region Constructors

		public UpdateService (IEventAggregator eventAggregator) {
			_eventAggregator = eventAggregator;
		}

		#endregion

		#region Private Methods

		private void CheckForUpdates (object state) {
			try {
				var currentVersion = new Version ((string) state);
				var reader = XmlReader.Create (UpdateFeed);
				var feed = SyndicationFeed.Load (reader);

				var items = feed.Items.Select (i => new { i.Id, Date = i.LastUpdatedTime.DateTime }).OrderBy (i => i.Date);
				var item = items.First ();

				var uri = new Uri (item.Id);
				var file = uri.Segments.Last ();

				var idx = file.LastIndexOf ("_");
				var zipIdx = file.LastIndexOf (".zip");
				var version = new Version (file.Substring (idx + 1, zipIdx - (idx + 1)));

				if (version > currentVersion) {
					_latestUpdateFile = file;
					_eventAggregator.GetEvent<UpdateFoundEvent> ().Publish (version.ToString ());
				}
				else {
					_latestUpdateFile = String.Empty;
				}
			}
			catch {
				return;
			}
		}

		private void DownloadLatestUpdate () {
			try {
				var dlUrl = DownloadPart + _latestUpdateFile;
				var client = new WebClient ();
				client.DownloadProgressChanged += (o, e) => _eventAggregator.GetEvent<UpdateProgressEvent> ().Publish (e);
				client.DownloadFileCompleted += (o, e) => _eventAggregator.GetEvent<UpdateCompleteEvent> ().Publish (_latestUpdateFile);
				client.DownloadFileAsync (new Uri (dlUrl), ".\\" + _latestUpdateFile);
			}
			catch {}
		}

		#endregion

		#region IUpdateService Members

		public void DownloadUpdate () {
			try {
				if (String.IsNullOrEmpty (_latestUpdateFile)) {
					return;
				}

				Task.Factory.StartNew (DownloadLatestUpdate);
			}
			catch {}
		}

		public void StartUpdateCheck (string currentVersion) {
			try {
				Task.Factory.StartNew (CheckForUpdates, currentVersion);
			}
			catch {}
		}

		#endregion
	}
}
